Skip to content

Conversation

caue-paiva
Copy link

For motivation see the following issue: #3452

Solution Overview: Server-Side Compression

This implementation provides a server-side only compression solution for dcc.Store components. The compression and decompression occur entirely on the server during callback execution, with the following key characteristics:

  • Automatic compression/decompression: Transparent to the developer once configured
  • Callback-level scope: Each callback can have its own compression configuration
  • Server-side processing: No client-side JavaScript modifications required
  • Graceful fallbacks: Robust error handling with fallback to uncompressed data

Important Note: This is explicitly a server-side solution. The client-side JavaScript cannot access or manipulate the compressed data - it only receives the final decompressed JSON payload.

Implementation Details

New Components Added

  1. BaseStoreCompressionManager: Abstract base class defining the compression interface
  2. GzipCompressionManager: Implementation using gzip algorithm (default)
  3. DeflateCompressionManager: Implementation using deflate algorithm
  4. BrotliCompressionManager: Implementation using Brotli algorithm (optional dependency)
  5. Helper function: get_compression_manager_from_kwargs() for parameter extraction

Core Functionality

  • Configurable compression levels: Algorithm-specific compression levels (1-9 for gzip/deflate, 0-11 for Brotli)
  • Size thresholds: Configurable minimum data size before compression is applied (default: 0 bytes)
  • Algorithm selection: Support for gzip, deflate, and Brotli compression algorithms
  • Automatic detection: Smart compression effectiveness checking with fallback to original data
  • Store component targeting: Only compresses dcc.Store component data properties

Integration with Callback System

The compression manager integrates seamlessly into the existing callback architecture:

  • Added CompressionManager parameter to callback decorators
  • Integrated compression/decompression into both sync and async callback wrappers
  • Maintains compatibility with existing callback features (background callbacks, clientside callbacks, etc.)
  • Uses kwargs-only approach for consistency with other optional callback parameters

Usage Example

# Create compression manager with custom settings
compression_manager = GzipCompressionManager(
    level=6,        # Compression level (1-9)
    threshold=1024  # Only compress data larger than 1KB
)

app.layout = html.Div([
    html.Button("Load Large Dataset", id="load-btn"),
    dcc.Store(id="data-store"),
    html.Div(id="output")
])

@app.callback(
    Output("data-store", "data"),
    Input("load-btn", "n_clicks"),
    CompressionManager=compression_manager
)
def load_large_dataset(n_clicks):
    if n_clicks:
        # Generate large dataset (would typically be from database/API)
        large_df = pd.DataFrame({
            'col1': range(10000),
            'col2': ['data'] * 10000,
            'col3': [i * 2.5 for i in range(10000)]
        })
        return large_df.to_dict('records')
    return dash.no_update

@app.callback(
    Output("output", "children"),
    Input("data-store", "data"),
    CompressionManager=compression_manager  # Same or different manager
)
def process_data(data):
    if data:
        return f"Processed {len(data)} records"
    return "No data loaded"

Summary

This feature provides a server-side compression solution for dcc.Store components that:

  • Significantly reduces network payload sizes for large datasets
  • Maintains full backward compatibility
  • Offers flexible configuration options
  • Includes comprehensive test coverage
  • Follows existing Dash architectural patterns

The implementation successfully addresses the performance bottlenecks identified in the original issue while maintaining the simplicity and reliability expected from the Dash framework.

Contributor Checklist

  • I have broken down my PR scope into the following TODO tasks
    • Implement compression functionality in a new file _compression.py
    • Allow for callback functionality to use the compression feature though injecting the compression manager class with kwargs (as argument to the @callback decorator)
    • I have written new unit tests to test the new compression functionality and how it interacts with the callback decorator
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

optionals

  • I have added entry in the CHANGELOG.md
  • If this PR needs a follow-up in dash docs, community thread, I have mentioned the relevant URLS as follows
    • this GitHub #PR number updates the dash docs
    • here is the show and tell thread in Plotly Dash community

@gvwilson gvwilson added feature something new P2 considered for next cycle community community contribution labels Oct 1, 2025
@gvwilson
Copy link
Contributor

gvwilson commented Oct 1, 2025

@caue-paiva thanks very much for the PR - I'll ask @T4rk1n to look it over when he gets a chance, but it may be a week or more before he can make time to evaluate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community community contribution feature something new P2 considered for next cycle
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants